package com.zero.insp.controller;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.zero.insp.common.PJson;
import com.zero.insp.common.PPageInfo;
import com.zero.insp.common.PResult;
import com.zero.insp.domain.TCompanyExh;
import com.zero.insp.domain.TCompanyExhExample;
import com.zero.insp.services.InspService;
import com.zero.insp.services.UploadService;
import com.zero.insp.utils.DateUtil;
import com.zero.insp.utils.ReadExcelUtils;
import com.zero.insp.utils.RunnerUtil;
import com.zero.insp.views.CompanyAnalView;
import com.zero.insp.views.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author : pengjie
 * @PackageName : com.zero.insp.controller
 * @Description : 巡检管理
 * @email : 627799251@qq.com
 * @Date : 2019/3/26 13:50
 */
@Api(value="管理员后台页面请求接口")
@RestController
public class WebInspController {
    private static final Logger logger = LoggerFactory.getLogger(WebInspController.class);

    @Value("${file.insp.load.path}")
    private String fileLoadPath;

    private static LoadingCache<String, Long> cache = null;

    static {
        cache = CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES)
                .build(new CacheLoader<String, Long>() {

                    @Override
                    public Long load(String key) throws Exception {
                        return 0L;
                    }
                });
    }

    @Autowired
    private InspService inspService;
    @Autowired
    private UploadService uploadService;

    private final ResourceLoader resourceLoader;

    @Autowired
    public WebInspController(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @ApiOperation("后台服务端-巡检信息列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name="period_num",value="期数",dataType="string", paramType = "query",example="一期"),
            @ApiImplicitParam(name="exh_area",value="展区",dataType="string", paramType = "query"),
            @ApiImplicitParam(name="insp_status",value="巡检状态；1未巡检，2已巡检",dataType="int", paramType = "query"),
            @ApiImplicitParam(name="insp_time",value="巡检时间",dataType="string", paramType = "query",example="2019-03-27"),
            @ApiImplicitParam(name="company_name",value="企业名称",dataType="string", paramType = "query")
    })
    @RequiresRoles(value = {"高级用户","巡检用户"}, logical = Logical.OR)
    @GetMapping("/web/v1/insp/list")
    public PResult<PPageInfo<TCompanyExh>> list(String period_num, String exh_area, @RequestParam(name= "insp_status",defaultValue = "0")int insp_status,
                                                String insp_time, String company_name,
                                                @RequestParam(name= "page",defaultValue = "1")int page,
                                                @RequestParam(name= "size",defaultValue = "10")int size) {
        TCompanyExhExample example = new TCompanyExhExample();
        TCompanyExhExample.Criteria criteria = example.createCriteria();

        if (period_num != null){
            criteria.andPeriodNumEqualTo(period_num);
        }
        if (exh_area != null){
            criteria.andExhAreaEqualTo(exh_area);
        }
        if (insp_time != null){
            Date cur = DateUtil.parseDate(insp_time, DateUtil.DEFAULT_PATTERN);
            Date start = DateUtil.getDayBegin(cur);
            Date end = DateUtil.getDayEnd(cur);
            criteria.andInspTimeBetween(start, end);
        }

        if (insp_status != 0){
            criteria.andInspStatusEqualTo(insp_status);
        }
        if (company_name != null){
            criteria.andCompanyNameLike("%"+company_name+"%");
        }

        example.setOrderByClause("company_name desc");

        PPageInfo<TCompanyExh> cc = inspService.query(example, page, size);

        return new PResult<>(cc);
    }
    @ApiOperation("后台服务端-巡检信息列表-V2")
    @ApiImplicitParams({
            @ApiImplicitParam(name="period_num",value="期数",dataType="string", paramType = "query",example="一期"),
            @ApiImplicitParam(name="exh_area",value="展区",dataType="string", paramType = "query"),
            @ApiImplicitParam(name="lib_nums",value="馆号，以逗号隔开，如：11.3,9.3",dataType="string", paramType = "query", example = "11.3,9.3"),
            @ApiImplicitParam(name="insp_status",value="巡检状态；1未巡检，2已巡检",dataType="int", paramType = "query"),
            @ApiImplicitParam(name="insp_stime",value="巡检开始时间",dataType="string", paramType = "query",example="2019-03-27"),
            @ApiImplicitParam(name="insp_etime",value="巡检结束时间",dataType="string", paramType = "query",example="2019-04-27"),
            @ApiImplicitParam(name="insp_user",value="巡检人姓名",dataType="string", paramType = "query",example = "张三"),
            @ApiImplicitParam(name="company_name",value="企业名称",dataType="string", paramType = "query")
    })
    @RequiresRoles(value = {"高级用户","巡检用户"}, logical = Logical.OR)
    @GetMapping("/web/v2/insp/list")
    public PResult<PPageInfo<TCompanyExh>> list2(String period_num, String exh_area, String lib_nums,
                                                 @RequestParam(name= "insp_status",defaultValue = "0")int insp_status,
                                                String insp_stime, String insp_etime, String insp_user,
                                                 String company_name,
                                                @RequestParam(name= "page",defaultValue = "1")int page,
                                                @RequestParam(name= "size",defaultValue = "10")int size) {
        TCompanyExhExample example = new TCompanyExhExample();
        TCompanyExhExample.Criteria criteria = example.createCriteria();

        if (period_num != null){
            criteria.andPeriodNumEqualTo(period_num);
        }
        if (exh_area != null){
            criteria.andExhAreaEqualTo(exh_area);
        }
        if (lib_nums != null){
            criteria.andLibNumIn(Arrays.asList(lib_nums.split(",")));
        }
        if (insp_stime != null & insp_etime != null){
            Date start = DateUtil.getDayBegin(DateUtil.parseDate(insp_stime, DateUtil.DEFAULT_PATTERN));
            Date end = DateUtil.getDayEnd(DateUtil.parseDate(insp_etime, DateUtil.DEFAULT_PATTERN));
            criteria.andInspTimeBetween(start, end);
        }

        if (insp_status != 0){
            criteria.andInspStatusEqualTo(insp_status);
        }
        if (insp_user != null){
            criteria.andInspUserEqualTo(insp_user);
        }
        if (company_name != null){
            criteria.andCompanyNameLike("%"+company_name+"%");
        }

        example.setOrderByClause("company_name desc");

        PPageInfo<TCompanyExh> cc = inspService.query(example, page, size);

        return new PResult<>(cc);
    }

    @ApiOperation("巡检详情")
    @ApiImplicitParam(name="insp_id",value="巡检记录id",dataType="string", paramType = "query")
    @RequiresUser
    @GetMapping("/web/v1/insp/detail")
    public PResult<TCompanyExh> detail(@RequestParam(name= "insp_id",required = true)long insp_id) {
        TCompanyExh cc = inspService.findByKey(insp_id);

        return  new PResult<>(cc);
    }

    @ApiOperation("后台服务端-巡检新增")
    @ApiImplicitParams({
            @ApiImplicitParam(name="period_num",value="期数",dataType="string", required = true, paramType = "query",example="一期"),
            @ApiImplicitParam(name="exh_area",value="展区",dataType="string", required = true, paramType = "query"),
            @ApiImplicitParam(name="area_num",value="区号",dataType="string", required = true, paramType = "query", example = "3.1D33-34,3.1E05-06"),
            @ApiImplicitParam(name="company_name",value="企业名称",dataType="string", required = true, paramType = "query"),
            @ApiImplicitParam(name="import_amount",value="进出口额，万元",dataType="double", required = true, paramType = "query"),
            @ApiImplicitParam(name="incr",value="增幅比例",dataType="double", required = true, paramType = "query")
    })
    @RequiresUser
    @PostMapping("/web/v1/insp/add")
    public PJson add(@RequestParam(name= "period_num",required = true)String period_num,
                     @RequestParam(name= "exh_area",required = true)String exh_area,
                     @RequestParam(name= "area_num",required = true)String area_num,
                     @RequestParam(name= "company_name",required = true)String company_name,
                     @RequestParam(name= "import_amount",required = true)double import_amount,
                     @RequestParam(name= "incr",required = true)double incr) {

        filterCompany(company_name, period_num);

        TCompanyExh companyExh = new TCompanyExh();
        companyExh.setPeriodNum(period_num);
        companyExh.setExhArea(exh_area);
        companyExh.setLibNum(getLibNum(area_num));
        companyExh.setChannelNum(getChannelNum(area_num));
        companyExh.setBooth(area_num);
        companyExh.setCompanyName(company_name);
        companyExh.setImportAmount(import_amount);
        companyExh.setIncr(incr);
        companyExh.setInspStatus(1);
        companyExh.setCreateTime(new Date());

        inspService.add(companyExh);

        return  PJson.succ();
    }

    private static String getLibNum(String area_num){
        String libNum = null;
        //11.3I25-26,11.3J13-15
        String[] libs = area_num.split(",");
        for (int i=0; i<libs.length;i++){
            String lib = libs[i];
            String channel = lib.replaceAll("[^a-z^A-Z]", "");
            libNum = lib.substring(0, lib.lastIndexOf(channel));
        }

        return libNum;
    }

    private static String getChannelNum(String area_num){
        String channel = "";
        //11.3I25-26,11.3J13-15
        String[] libs = area_num.split(",");
        for (int i=0; i<libs.length;i++){
            String lib = libs[i];
            String cc = lib.replaceAll("[^a-z^A-Z]", "");
            if (channel == ""){
                channel = channel + cc;
            }else {
                channel = channel + "," + cc;
            }
        }
        return channel;
    }

    @ApiOperation("巡检删除")
    @ApiImplicitParam(name="insp_id",value="巡检记录id",dataType="string", paramType = "query")
    @RequiresUser
    @DeleteMapping("/web/v1/insp/del")
    public PJson del(@RequestParam(name= "insp_id",required = true)long insp_id) {
        inspService.delete(insp_id);

        return  PJson.succ();
    }
    @ApiOperation("巡检批量删除")
    @ApiImplicitParam(name="insp_ids",value="批量删除id，格式以逗号隔开",dataType="string", paramType = "query",example="12,13,14")
    @RequiresUser
    @DeleteMapping("/web/v1/insp/bdel")
    public PJson bdel(@RequestParam(name= "insp_ids",required = true)String insp_ids) {

        String[] ids = insp_ids.split(",");
        for(int i=0; i<ids.length; i++){
            inspService.delete(Long.valueOf(ids[i]));
        }

        return  PJson.succ();
    }
    private void filterCompany(String company_name, String period_num){
        TCompanyExh companyExh = inspService.findByCompanyName(company_name, period_num);
        if (companyExh != null){
            inspService.delete(companyExh.getId());
        }
    }

    @ApiOperation("巡检批量导入-企业信息")
    @RequiresUser
    @PostMapping("/web/v1/insp/cbatch")
    public PJson cbatch(MultipartFile cbatch_file) throws Exception{

        User user = (User) SecurityUtils.getSubject().getPrincipal();
        String cacheKey = user.getUid()+cbatch_file.getOriginalFilename();

        if (cache.get(cacheKey) == 1){
            return PJson.fail().msg("请勿频繁上传相同文件，请5分钟后再试。");
        }

        cache.put(cacheKey, 1L);

        RunnerUtil.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    cbatchWork(cbatch_file);
                } catch (IOException e) {
                    logger.info("导入企业数据文件出现问题", e);
                }
            }
        });

        return  PJson.succ();
    }
    private void cbatchWork(MultipartFile cbatch_file) throws IOException {

        Workbook workbook = ReadExcelUtils.getWorkbok(cbatch_file.getInputStream(),cbatch_file.getOriginalFilename());
        //Workbook workbook = WorkbookFactory.create(is); // 这种方式 Excel2003/2007/2010都是可以处理的

        int sheetCount = workbook.getNumberOfSheets(); // Sheet的数量
        /**
         * 设置当前excel中sheet的下标：0开始
         */
//            Sheet sheet = workbook.getSheetAt(0);   // 遍历第一个Sheet
        Sheet sheet = workbook.getSheetAt(0);   // 遍历第三个Sheet
        // 为跳过第一行目录设置count
        int count = 0;
        for (Row row : sheet) {
            logger.info("正在导入企业会展数据，当前企业:" + row.getCell(2).getStringCellValue());
            try {
                // 跳过第4行的目录
                if (count < 4) {
                    count++;
                    continue;
                }
                //如果当前行没有数据，跳出循环
                if (row.getCell(0).toString().equals("")) {
                    continue;
                }
                TCompanyExh companyExh = new TCompanyExh();

                //企业名称
                String company_name = row.getCell(2).getStringCellValue();
                companyExh.setCompanyName(company_name);

                //展区
                String zq = row.getCell(3).getStringCellValue();
                companyExh.setExhArea(zq);
                //摊位号
                String tw = row.getCell(11).getStringCellValue();
                companyExh.setBooth(tw);

                //期数
                String qs = row.getCell(13).getStringCellValue();
                companyExh.setPeriodNum(qs);
                //馆号
                companyExh.setLibNum(getLibNum(tw));
                //通道号A,C
                companyExh.setChannelNum(getChannelNum(tw));
                //巡检状态
                companyExh.setInspStatus(1);
                companyExh.setCreateTime(new Date());

                //过滤企业
                filterCompany(company_name, qs);
                inspService.add(companyExh);

            }catch (Exception e){
                logger.info("当前企业会展数据异常 , 企业名称:" + row.getCell(2).getStringCellValue(), e);
            }
        }
        logger.info("导入企业会展数据完成...");

    }
    @ApiOperation("巡检批量导入-进出口数据")
    @RequiresUser
    @PostMapping("/web/v1/insp/ibatch")
    public PJson ibatch(MultipartFile ibatch_file) throws Exception {

        User user = (User) SecurityUtils.getSubject().getPrincipal();
        String cacheKey = user.getUid()+ibatch_file.getOriginalFilename();

        if (cache.get(cacheKey) == 1){
            return PJson.fail().msg("请勿频繁上传相同文件，请5分钟后再试。");
        }

        cache.put(cacheKey, 1L);

        RunnerUtil.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    ibatchWork(ibatch_file);
                } catch (IOException e) {
                    logger.info("导入出口数据文件出现问题", e);
                }
            }
        });

        return  PJson.succ();
    }

    private void ibatchWork(MultipartFile ibatch_file) throws IOException {

        Workbook workbook = ReadExcelUtils.getWorkbok(ibatch_file.getInputStream(),ibatch_file.getOriginalFilename());
        //Workbook workbook = WorkbookFactory.create(is); // 这种方式 Excel2003/2007/2010都是可以处理的

        int sheetCount = workbook.getNumberOfSheets(); // Sheet的数量
        /**
         * 设置当前excel中sheet的下标：0开始
         */
//            Sheet sheet = workbook.getSheetAt(0);   // 遍历第一个Sheet
        Sheet sheet = workbook.getSheetAt(0);   // 遍历第三个Sheet
        // 为跳过第一行目录设置count
        int count = 0;
        for (Row row : sheet) {
            logger.info("正在导入企业出口数据，当前企业:" + row.getCell(0).getStringCellValue());

            try {
                // 跳过第4行的目录
                if (count < 6) {
                    count++;
                    continue;
                }
                //如果当前行没有数据，跳出循环
                if (row.getCell(0).toString().equals("")) {
                    continue;
                }
                String company_name = row.getCell(0).getStringCellValue();
                double money = row.getCell(2).getNumericCellValue();
                double incr = row.getCell(4).getNumericCellValue();

                TCompanyExh companyExh = new TCompanyExh();
                companyExh.setImportAmount(money);
                companyExh.setIncr(incr);

                inspService.edit(companyExh, company_name);

            }catch (Exception e){
                logger.info("当前企业出口数据异常 , 企业名称:" + row.getCell(0).getStringCellValue(), e);
            }
        }
        logger.info("导入企业出口数据完成...");
    }

    @ApiOperation("巡检统计")
    @GetMapping("/web/v1/insp/anal")
    public PResult<List<CompanyAnalView>> anal() {
        List<CompanyAnalView> result = inspService.companyAnal(null);

        return new PResult<>(result);
    }

    @ApiOperation("前端-确认巡检")
    @ApiImplicitParam(name="insp_id",value="记录id",dataType="string", paramType = "query")
    @RequiresUser
    @PostMapping("/web/v1/insp/fixed")
    public PJson fixed(@RequestParam(name= "insp_id",required = true)long insp_id) {
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        TCompanyExh companyExh = new TCompanyExh();
        companyExh.setInspStatus(2);
        companyExh.setInspUser(user.getNick());
        companyExh.setInspTime(new Date());

        TCompanyExh companyDB = inspService.findByKey(insp_id);

        inspService.edit(companyExh, companyDB.getCompanyName());

        return PJson.succ();
    }
    @ApiOperation("前端-上传巡检报告")
    @RequiresUser
    @PostMapping("/web/v1/insp/report")
    public PJson report(@RequestParam(name= "insp_id",required = true)long insp_id, MultipartFile report_file) throws Exception{
        // 保存文件到本地
        String localUrl = uploadService.tranferFile(report_file, "INSP", fileLoadPath);

        TCompanyExh companyExh = new TCompanyExh();
        companyExh.setInspImport(localUrl);

        inspService.edit(companyExh, insp_id);

        return PJson.succ();
    }

    @ApiOperation("前端-下载巡检报告")
    @GetMapping("/web/v1/insp/down")
    public PJson firmDown(String file_path, HttpServletResponse response) throws Exception{

        if (file_path == null) {
            //return (ResponseEntity) ResponseEntity.notFound().build();
            return PJson.fail().msg("文件路径不存在");
        }
        //下载固件
        downLoad(file_path, response, false);
/*
        try {

            Resource resource = resourceLoader.getResource("file:" + file_path);
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(resource.getFilename(), "UTF-8"));
            return ResponseEntity.ok(resource);
        } catch (Exception e) {
            logger.info("download firmware error .", e);
            return ResponseEntity.badRequest().build();
        }
*/
        return PJson.succ();
    }
    public void downLoad(String filePath, HttpServletResponse response, boolean isOnLine) throws Exception {
        File f = new File(filePath);
        if (!f.exists()) {
            response.sendError(404, "File not found!");
            return;
        }
        BufferedInputStream br = new BufferedInputStream(new FileInputStream(f));
        OutputStream out = response.getOutputStream();
        try {
            byte[] buf = new byte[1024];
            int len = 0;

            response.reset(); //  非常重要
            if (isOnLine) { // 在线打开方式
                URL u = new URL("file:///" + filePath);
                response.setContentType(u.openConnection().getContentType());
                response.setHeader("Content-Disposition", "inline; filename=" + f.getName());
                // 文件名应该编码成UTF-8
            } else { // 纯下载方式
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(f.getName(), "UTF-8"));
            }
            while ((len = br.read(buf)) > 0)
                out.write(buf, 0, len);
        } catch (Exception e) {
        }
        finally {
            br.close();
        }

    }
}
